package edu.hawaii.duedates.results;

import java.util.Comparator;
import org.junit.Test; 
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.fail;

/**
 * Some tests to check that the BorrowedItem class functions as expected.
 * 
 * @author Erin Kim and Arthur Shum
 */
public class TestBorrowedItem {
  
  private static final String dateA = "20090510";
  private static final String libraryA = "libraryA";
  private static final String resultsA = "A";
  private final BorrowedItem itemA = new BorrowedItem(libraryA, dateA, resultsA);
  private final BorrowedItem itemA2 = new BorrowedItem(libraryA, dateA, resultsA);
  private final BorrowedItem itemZ = new BorrowedItem(libraryA, dateA, "Z");

  private final BorrowedItem itemB = new BorrowedItem("libraryB", "20081005", "B");
  private final BorrowedItem itemC = new BorrowedItem("libraryC", "20080515", "C");

  /**
   * Tests that dueDateComparator returns a comparator for BorrowedItem objects, and that the
   * comparator's compare method works as specified in the Comparator API.
   */
  @Test
  public void testDueDateComparator() {
    Comparator<BorrowedItem> ddc = BorrowedItem.dueDateComparator;
    // Test that sgn(compare(x,y)) == -sgn(compare(y,x))
    int aCompB = ddc.compare(itemA, itemB);
    int bCompA = ddc.compare(itemB, itemA);
    assertEquals("Should have the same sign", Math.signum(aCompB), -Math.signum(bCompA), 0.01);

    // Test transitivity.
    int bCompC = ddc.compare(itemB, itemC);
    int aCompC = ddc.compare(itemA, itemC);
    assertTrue("Should be positive", aCompB > 0);
    assertTrue("Should be positive", bCompC > 0);
    assertTrue("Should be positive", aCompC > 0);
    
    // Test that compare(x,y)==0 implies sgn(compare(x,z))==sgn(compare(yz)).
    int aCompA2 = ddc.compare(itemA, itemA2);
    int a2CompC = ddc.compare(itemA2, itemC);
    assertEquals("Should be zero", 0, aCompA2);
    assertEquals("Should have the same sign", Math.signum(aCompC), Math.signum(a2CompC), 0.01);
    
    // Test inequality
    int aCompZ = ddc.compare(itemA, itemZ);
    assertNotSame("Should not be zero", 0, aCompZ);    
  }

  /**
   * Tests that libraryComparator returns a comparator for BorrowedItem objects, and that the
   * comparator's compare method works as specified in the Comparator API.
   */
  @Test
  public void testLibraryComparator() {
    Comparator<BorrowedItem> lnc = BorrowedItem.libraryComparator;
    
    // Test that sgn(compare(x,y)) == -sgn(compare(y,x))
    int aCompB = lnc.compare(itemA, itemB);
    int bCompA = lnc.compare(itemB, itemA);
    assertEquals("Should be equal", Math.signum(aCompB), -Math.signum(bCompA), 0.01);

    // Test transitivity.
    int bCompC = lnc.compare(itemB, itemC);
    int aCompC = lnc.compare(itemA, itemC);
    assertTrue("Should be negative", aCompB < 0);
    assertTrue("Should be negative", bCompC < 0);
    assertTrue("Should be negative", aCompC < 0);

    // Test that compare(x,y)==0 implies sgn(compare(x,z))==sgn(compare(yz)).
    int aCompA2 = lnc.compare(itemA, itemA2);
    int a2CompC = lnc.compare(itemA2, itemC);
    assertEquals("Should be zero", 0, aCompA2);
    assertEquals("Should be equal", Math.signum(aCompC), Math.signum(a2CompC), 0.01);

    // Test inequality
    int aCompZ = lnc.compare(itemA, itemZ);
    assertNotSame("Should not be zero", 0, aCompZ);      
  }
  
  /**
   * Test that the Constructor throws an exception for null inputs.
   */
  @Test (expected = NullPointerException.class)
  public void testConstructor() {
    String blankLibrary = null;
    String blankDate = null;
    String blankResults = null;
    new BorrowedItem(blankLibrary, blankDate, blankResults);
    fail("Should not get here");
  }
  
 
  /**
   * Tests that the correct library name is returned. 
   */
  @Test
  public void testGetLibraryName() {
    assertEquals("Expecting \"libraryA\"", "libraryA", itemA.getLibraryName());
  }
  
  /**
   * Tests that the expected due date is returned.
   */
  @Test
  public void testGetDueDate() {
    assertEquals("Expecting \"20090510\"", "20090510", itemA.getYyyymmddDueDate());
  }

  /**
   * Tests that the expected string is returned.
   */
  @Test
  public void testGetFormattedResults() {
    assertEquals("Expecting \"A\"", "A", itemA.getFormattedResults());
  }
  
  /**
   * Tests that the toString method works as expected.
   */
  @Test
  public void testToString() {
    assertEquals("Expecting \"A\"", "A", itemA.toString());
  }

}
